#coding:utf8
'''
    功能函数
'''

from flask import make_response, request
from functools import wraps
from io import BytesIO
from urllib.request import urlopen, quote
from urllib.parse import urlencode

from _sys.models import MongodbOperations, ReadConfig, CreateCodeImg
from _sys.code import orderStatusDict, activityTypeDict, dbNameDict
from pystrich.code128 import Code128Encoder
from pystrich.qrcode import QRCodeEncoder

import json, time, uuid, random
import re
import hashlib
import jwt
import requests
import base64

mgOpt = MongodbOperations()
config = ReadConfig().read()

def md5Encode(str):
    '''
        针对密码进行md5加密
    :param str:
    :return:
    '''
    md5 = hashlib.md5()
    md5.update(str.encode('utf-8'))
    return md5.hexdigest()

def allow_cross(fun):
    '''
        实现跨域访问装饰器--后期改造白名单
    :param fun:
    :return:
    '''

    @wraps(fun)
    def wrapper_fun(*args, **kwargs):
        rst = make_response(fun(*args, **kwargs))
        rst.headers['Access-Control-Allow-Origin'] = '*'
        rst.headers['Access-Control-Allow-Methods'] = 'PUT,GET,POST,DELETE'
        allow_headers = "Referer,Accept,Origin,User-Agent"
        rst.headers['Access-Control-Allow-Headers'] = allow_headers
        return rst
    return wrapper_fun

def create_phone_code():
    '''
        生成短信验证码 phone code
    :return:
    '''
    chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
    x = random.choice(chars), random.choice(chars), random.choice(chars), random.choice(chars), random.choice(chars)
    code = ''.join(x)
    return code

def save_barcode(code):
    '''
        生成条形码 存储
    :param code:
    :return:
    '''
    encoder = Code128Encoder(code)
    encoder.save("code128of_jpg/" + code + ".jpg")

def save_qr_code(code):
    '''
        生成二维码 存储
    :param code:
    :return:
    '''
    encoder = QRCodeEncoder(code)
    encoder.save("qrcodeof_jpg/" + code + ".jpg")

def create_serial_num(total):
    '''
        生成序列号
    :param total:
    :return:
    '''
    count = 0
    values = []
    time_stamp = int(''.join(str(time.time()).split('.'))[-4:])

    def intercept_str(str):
        s_1 = random.randint(0, 30)
        s_2 = random.randint(2, 28)
        s_3 = random.randint(4, 26)
        s_4 = random.randint(6, 24)
        str_1 = str[s_1:s_1 + 2]
        str_2 = str[s_2:s_2 + 2]
        str_3 = str[s_3:s_3 + 2]
        str_4 = str[s_4:s_4 + 2]
        return str_1 + str_2 + str_3 + str_4

    uid = ''.join(str(uuid.uuid4()).split('-'))
    s = intercept_str(uid)
    while count < int(total):
        count = count + 1
        time_stamp = time_stamp + 1
        code = s + str(time_stamp)
        save_barcode(code)
        save_qr_code(code)
        values.append(code)
    return values

def get_visitor_ip_addr(ip,m='GET'):
    '''
        根据访问则ip 获取地址
    :param appkey:
    :param m:
    :return:
    '''
    url = "http://apis.juhe.cn/ip/ip2addr"
    params = {
        "ip": ip,  # 需要查询的IP地址或域名
        "key": 'be345d2d311662ce0a79db73119dba30',  # 应用APPKEY(应用详细页查询)
        "dtype": "json",  # 返回数据的格式,xml或json，默认json
    }
    params = urlencode(params)
    if m == "GET":
        f = urlopen("%s?%s" % (url, params))
    else:
        f = urlopen(url, params)

    content = f.read()
    res = json.loads(content)
    if res:
        error_code = res["error_code"]
        if error_code == 0:
            # 成功请求
            return res
        else:
            print("%s:%s" % (res["error_code"], res["reason"]))
            return False
    else:
        print("request api error")
        return False

def get_express_com(appkey, m='GET'):
    '''
        获取快递公司编号  -默认GET方法
    :param appkey:
    :return:
    '''
    url = "http://v.juhe.cn/exp/com"
    params = {"key": appkey}
    params = urlencode(params)
    if m == "GET":
        f = urlopen("%s?%s" % (url, params))
    else:
        f = urlopen(url, params)

    content = f.read()
    res = json.loads(content)
    if res:
        error_code = res["error_code"]
        if error_code == 0:
            # 成功请求
            return res
        else:
            print("%s:%s" % (res["error_code"], res["reason"]))
            return False
    else:
        print("request api error")
        return False

def get_express_no_info(appkey, com, no, m='GET'):
    '''
        获取快递单号信息
    :param appkey:
    :param m:
    :return:
    '''
    if not com or not no:
        print('com and no are empty')
        return False

    url = "http://v.juhe.cn/exp/index"
    params = {
        "com": com,  # 需要查询的快递公司编号
        "no": no,  # 需要查询的订单号
        "key": appkey,  # 应用APPKEY(应用详细页查询)
        "dtype": "json",  # 返回数据的格式,xml或json，默认json

    }
    params = urlencode(params)
    if m == "GET":
        f = urlopen("%s?%s" % (url, params))
    else:
        f = urlopen(url, params)

    content = f.read()
    res = json.loads(content)
    if res:
        error_code = res["error_code"]
        if error_code == 0:
            # 成功请求
            return res
        else:
            print("%s:%s" % (res["error_code"], res["reason"]))
            return False
    else:
        print("request api error")
        return False

def send_sms(appkey, mobile, tpl_id, tpl_value):
    '''
        发送短信验证码
    :param appkey:
    :param mobile:
    :param tpl_id:
    :param tpl_value:
    :return:
    '''
    sendUrl = 'http://v.juhe.cn/sms/send' #短信发送的URL,无需修改
    params = 'key=%s&mobile=%s&tpl_id=%s&tpl_value=%s' % \
             (appkey, mobile, tpl_id, quote(tpl_value))  # 组合参数
    wp = urlopen(sendUrl + "?" + params)
    content = wp.read()  # 获取接口返回内容
    result = json.loads(content)

    if result:
        error_code = result['error_code']
        if error_code == 0:
            # 发送成功
            smsid = result['result']['sid']
            return smsid
        else:
            # 发送失败
            print("send sms error :(%s) %s" % (error_code, result['reason']))
            return False
    else:
        # 请求失败
        print("request send sms error")
        return False

def inquiry_vip(uid):
    '''
        调查用户是否可成为vip
    :param uid:
    :return:
    '''
    year = time.strftime("%Y", time.localtime())  # 确定所在年份
    timeStart = time.mktime(time.strptime(year + '-01-01 00:00:00', "%Y-%m-%d %H:%M:%S"))  # 检索订单开始时间
    timeEnd = time.mktime(time.strptime(year + '-12-31 23:59:59', "%Y-%m-%d %H:%M:%S"))
    params = {
        'table': dbNameDict['userOrderData'],
        'query':{
            'order_finish_time':{
                '$gte': timeStart,
                '$lte': timeEnd
            },
            "uid": uid,    # 所属用户uid
            'order_status': orderStatusDict['Completed']   # 订单状态为完结
        }
    }
    if not uid:
        print('need uid')
        return False
    acquiredList = list( mgOpt.find_many(params['table'], params['query']) )
    if len(acquiredList) == 0:   # 用户本年度无订单
        print('user has no order in this year.')
        return False
    # order_amount 订单金额
    userOrderAmountOfThisYear = 0
    for order in acquiredList:
        userOrderAmountOfThisYear = userOrderAmountOfThisYear + int(order['order_amount']['rmb'])
    vip_amount = config.get('vip_amount')
    if userOrderAmountOfThisYear < vip_amount:   # 小于要求 不能成为vip
        return False
    else:
        print('Congratulations, new VIP')
        return True

def calculating_product_activity_price(pid, lang,is_vip=False):
    '''
        计算商品活动价格 -- 普通折扣，会员折扣
    :param pid:
    :param is_vip:
    :return:
    '''
    if not pid or not lang:
        print('lack of necessary parameters')
        return False

    query = {
        "pid": pid # 商品pid
    }
    res = {} # 活动优惠信息 --可能有多个价格
    productData = mgOpt.find_one(dbNameDict['productData'], query)
    AccessActivitiesIds = productData['access_activities']  # 商品享受的活动 list
    for actId in AccessActivitiesIds:
        actInfo = mgOpt.find_one(dbNameDict['activityData'],{'act_id': actId}) # 获取相应活动信息
        if actInfo['act_status'] == '0': # 活动状态正常
            if actInfo['type'] == 'discount':  # 普通折扣
                actPrice = float(productData['p_price'][lang]) * float(actInfo['discount'])
                res[actInfo['name']] = {
                    'name_lg': actInfo['name_lg'],
                    'active_price': actPrice,
                    'type': activityTypeDict['discount']
                }
            elif actInfo['type'] == 'vip':  # vip 折扣
                if is_vip: # 是vip
                    actPrice = float(productData['p_price'][lang]) * float(actInfo['discount'])
                    res[actInfo['name']] = {
                        'name_lg': actInfo['name_lg'],
                        'active_price': actPrice,
                        'type': activityTypeDict['vip']
                    }
    return res

def calculating_order_amount(oid):
    '''
        计算订单总额  --满减 抵扣
        同时的满减活动只能存在一个
    :param oid:
    :return:
    '''
    orderData = mgOpt.find_one(dbNameDict['userOrderData'], {'oid': oid})
    actFullSubtractionData = mgOpt.find_one(dbNameDict['promotionalData'], {'type':'fullSubtraction', 'ptl_status': '0'})
    actDeductibleData = mgOpt.find_one(dbNameDict['promotionalData'], {'type':'deductible', 'ptl_status': '0'})
    res = {}
    if actFullSubtractionData: # 存在满减
        orderFullAmount = float(actFullSubtractionData['full_amount'])
        reliefAmount = float(actFullSubtractionData['relief_amount'])
        orderAmount = float(orderData['order_amount'])

        if orderAmount >= orderFullAmount: # 满足条件
            orderAmount = orderAmount - reliefAmount
            res[actFullSubtractionData['name']] = {
                'name_lg': actFullSubtractionData['name_lg'],
                'type': activityTypeDict['fullSubtraction'],
                'active_amount': str(orderAmount)
            }
    if actDeductibleData: # 存在抵扣 --抵扣需要输入抵扣码
        res[actDeductibleData['name']] = {
            'name_lg': actDeductibleData['name_lg'],
            'type': activityTypeDict['deductible'],
            'active_amount': orderData['order_amount'] #此时order金额并没有变化
        }
    return res


def email_html(code, model_id, user_name, to):
    '''
        # 邮件内容实现
    :param toName:  收信地址
    :param link:    连接
    :param model_id:   数据库设置邮件模板
    :return:
    '''
    if user_name and code and model_id:
        modelData = mgOpt.find_one(dbNameDict['adminSettingsEmail'], {"model_id": model_id}) # 获取模板内容
        html = modelData['html']
        # 正则匹配 替换内容
        pattern_to = re.compile(r'%userName%')
        pattern_code = re.compile(r'%code%')
        result1, number1 = pattern_to.subn(user_name, html)
        result2, number2 = pattern_code.subn(code, result1)
        if result2:
            mgOpt.insert_one(dbNameDict['msgCodeData'], {"u_mail": to, 'm_code':code, 'status':'1','create_time':time.time(),
                                                         'act_time':''})
            return result2

def build_url(to, baseUrl, _type):
    '''
        # 构建验证连接
    :param type: register 注册验证 or reset 重置密码
    :param type: to 收件人
    :return:
    '''

    # 拼接连接url
    def url_join(base, params):
        item = params.items()
        urls = "?"
        for i in item:
            (key, value) = i
            temp_str = key + "=" + value
            urls = urls + temp_str + "&"
        url = base + urls[:len(urls) - 1]
        return url

    auth_payload = {
        'uid': to,
        'time':time.time(),
        'overtime': time.time() + 3600,
        'type':_type
    }
    token = jwt.encode(auth_payload, config['token'], algorithm='HS256').decode('utf-8') # 构建验证token
    #根据token 内容验证#
    url = url_join(baseUrl, {'token':token,'uEmail':to})
    return url

def send_email_by_model(send_to_url, user_name, model_id, _type='register'):
    '''
        模板邮件发信 --只发送系统邮件 不发送活动邮件
    :return:
    '''
    sendUrl = "http://api.sendcloud.net/apiv2/mail/send"
    API_USER =config.get('send_mail_api_user')
    API_KEY = config.get('send_mail_api_key')
    if type == 'register':
        baseUrl = 'http://kplus-helmet.com/reg'
        subject = 'KPLUS-HELMET 激活邮件'
    else:
        baseUrl = 'http://kplus-helmet.com/rst'
        subject = 'KPLUS-HELMET 重置密码'

    if send_to_url and model_id:
        #link = build_url(send_to_url, baseUrl, _type)
        code = create_phone_code()
        html = email_html(code, model_id, user_name, send_to_url)
        # 构建发送参数
        params = {
            'apiUser': API_USER,
            'apiKey': API_KEY,
            'to': send_to_url,
            'subject': subject,
            'from': 'kplus@tianqitech.com',
            'fromName': 'kplus-helmet.com',
            'html': html
        }
        r = requests.post(sendUrl, data=params)
        if json.loads(r.text)['statusCode'] == 200:
            return {'code':200, 'data':json.loads(r.text)['message'] }
        return {'code':400, 'data': json.loads(r.text)['message']}
    # 参数缺失
    print('lack of necessary parameters')
    return False

def create_code_img():
    '''
          生成验证图片
    :return:
    '''
    tmp = "abcdefghjkmnpqrstwxyz1234567890ABCDEFGHJKLMNPQRSTWXYZ"
    s = ''.join(random.sample(list(tmp), 5))
    pic = CreateCodeImg(s, (120, 50), 'white')
    pic.create_pic()
    pic.create_point()
    pic.create_line()
    pic.create_text()
    pic.opera()
    buffer = BytesIO()
    pic.img.save(buffer, format="JPEG")
    img_bs64 = base64.b64encode(buffer.getvalue()).decode('utf-8')
    res = {
        'code': s,
        'base64':img_bs64
    }
    return res

def admin_open_ips(visit_ip):
    '''
        管理员IP地址白名单验证
    :param ip:
    :return:
    '''
    #ips_arr = config['admin-ips'].split(';')
    #for ip in ips_arr:
        #if ip == visit_ip:
            #return True  # ip 地址存在于白名单
    return True

def had_power(ps, powers):
    '''
        管理员权限验证
    :param ps:
    :param powers:
    :return:
    '''
    for power in powers:
        if power == ps:
            return True
    return False


def parse_param_info(param):
    '''
        # 解压参数信息 '|'
    :param param:
    :return:
    '''

    res = param.split('|')
    return res


def format_words(parse_arr):
    '''
        # 解压文字信息
    :param parse_arr:
    :return:
    '''
    _dict = dict()
    if type(parse_arr) == list:
        for i in parse_arr:
            try:
                a = i.split(':')
                _dict[a[0]] = a[1]
            except:
                print('error of p')
    return _dict












